package service

import (
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"gitee.com/sdumeeting/sfu-server/global"
	"gitee.com/sdumeeting/sfu-server/internal/model"
	"io/ioutil"
	"net/http"
	"strings"
	"time"
)

var meetingList *model.MeetingList

func init() {
	meetingList = model.NewMeetingList()

	// 定期清除过期会议
	go cleanUpExpiredMeetings(30 * time.Second)
}

type CreateMeetingHandler struct{}

// 创建会议
// 用户向会议管理中心提交创建请求后
// 会议管理中心会向合适的 sfu 发起创建请求
// 请求参数包括会议号、会议模式、会议人数限制
// 如果有错误，报 http.StatusBadRequest 错误
func (h *CreateMeetingHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	// 判断该请求是否来自会议管理中心
	if strings.Split(r.RemoteAddr, ":")[0] != global.MeetingManager.Host {
		fmt.Println("address error")
		w.WriteHeader(http.StatusBadRequest)
		return
	}

	// 从 r.Body 中读取数据
	body, err := ioutil.ReadAll(r.Body)
	if err != nil {
		fmt.Println(err.Error())
		w.WriteHeader(http.StatusBadRequest)
		return
	}

	// 解析读取到的数据
	var data map[string]interface{}
	err = json.Unmarshal(body, &data)
	if err != nil {
		fmt.Println(err.Error())
		w.WriteHeader(http.StatusBadRequest)
		return
	}

	var meetingId, limit, pattern int

	// 获取会议号
	meetingId = int(data["meetingId"].(float64))

	// 如果该会议已存在，则返回错误
	meeting := meetingList.GetMeetingById(meetingId)
	if meeting != nil {
		fmt.Println("meeting already exists")
		w.WriteHeader(http.StatusBadRequest)
		return
	}

	// 获取会议人数
	limit = int(data["limit"].(float64))

	// 获取会议模式
	pattern = int(data["pattern"].(float64))

	// 创建会议
	meeting = model.NewMeeting(meetingId, limit, pattern)
	meetingList.AddMeeting(meeting)

	w.WriteHeader(http.StatusOK)
}

// 结束会议
func endMeeting(meetingId int) error {
	// 向媒体服务器发起结束会议的请求内容
	endInfo := make(map[string]interface{})
	endInfo["meetingId"] = meetingId
	endInfo["port"] = global.ServerSetting.Port

	// 将 map 转换成 json 格式的字符数组
	body, err := json.Marshal(endInfo)
	if err != nil {
		return err
	}

	// 创建 bytes.Reader，并将请求体字符数组传入
	// 该结构体实现了 io.Reader 接口，可作为 http.Post() 的第三个参数
	reader := bytes.NewReader(body)

	// 在媒体服务器创建会议
	var resp *http.Response
	resp, err = http.Post("http://"+global.MeetingManager.GetAddr()+"/end",
		"application/json;charset=utf-8", reader)

	// 如果有错误发生或状态码不是 200，返回相应的错误信息
	if err != nil || resp.StatusCode != http.StatusOK {
		return errors.New("request was aborted")
	}

	return nil
}

// 清除过期会议
func cleanUpExpiredMeetings(freq time.Duration) {
	for {
		time.Sleep(freq)

		// 遍历列表中所有会议
		for id, meeting := range meetingList.GetMeetings() {
			// 如果某个会议过期
			if meeting.IsExpired() {
				// 向会议管理中心发起结束会议的请求
				err := endMeeting(id)
				if err != nil {
					fmt.Println(err)
				}

				// 从列表中移除该会议
				meetingList.DeleteMeeting(id)
			}
		}
	}
}
